#ifndef SPONGE_LIBSPONGE_TCP_RECEIVER_HH
#define SPONGE_LIBSPONGE_TCP_RECEIVER_HH

#include "byte_stream.hh"
#include "stream_reassembler.hh"
// #include "tcp_helpers/tcp_segment.hh"
#include "tcp_segment.hh"
#include "wrapping_integers.hh"

#include <optional>

//! \brief The "receiver" part of a TCP implementation.

//! Receives and reassembles segments into a ByteStream, and computes
//! the acknowledgment number and window size to advertise back to the
//! remote TCPSender.
class TCPReceiver {
  //! Our data structure for re-assembling bytes.
  StreamReassembler _reassembler;

  //! The maximum number of bytes we'll store.
  size_t _capacity;
  bool _syn{false};
  bool _fin{false};
  WrappingInt32 _isn;

 public:
  //! \brief Construct a TCP receiver
  //!
  //! \param capacity the maximum number of bytes that the receiver will
  //!                 store in its buffers at any give time.
  TCPReceiver(const size_t capacity) : _reassembler(capacity), _capacity(capacity), _isn(0) {}

  //! \name Accessors to provide feedback to the remote TCPSender
  //!@{

  //! \brief The ackno that should be sent to the peer
  //! \returns empty if no SYN has been received
  //!
  //! This is the beginning of the receiver's window, or in other words, the sequence number
  //! of the first byte in the stream that the receiver hasn't received.
  std::optional<WrappingInt32> ackno() const;

  //! \brief The window size that should be sent to the peer
  //!
  //! Operationally: the capacity minus the number of bytes that the
  //! TCPReceiver is holding in its byte stream (those that have been
  //! reassembled, but not consumed).
  //!
  //! Formally: the difference between (a) the sequence number of
  //! the first byte that falls after the window (and will not be
  //! accepted by the receiver) and (b) the sequence number of the
  //! beginning of the window (the ackno).
  size_t window_size() const;
  //!@}

  //! \brief number of bytes stored but not yet reassembled
  size_t unassembled_bytes() const { return _reassembler.unassembled_bytes(); }

  //! \brief handle an inbound segment
  //! \returns `true` if any part of the segment was inside the window
  bool segment_received(const TCPSegment &seg);

  //! \name "Output" interface for the reader
  //!@{
  ByteStream &stream_out() { return _reassembler.stream_out(); }
  const ByteStream &stream_out() const { return _reassembler.stream_out(); }
  //!@}

  auto get_window_left() const -> uint64_t {
    // 加SYN
    auto abs_ack_no = _reassembler.get_next_index() + 1;
    // 加FIN
    if (_reassembler.stream_out().input_ended()) {
      abs_ack_no += 1;
    }
    return abs_ack_no;
  }
};

#endif  // SPONGE_LIBSPONGE_TCP_RECEIVER_HH
